Imports System.Threading
Imports System.IO
Imports BikiSoft

Namespace Comm
    <ObfuscationAttribute(Exclude:=True, ApplyToMembers:=True)> _
    Public Class UsbCommunicationHandle
        Implements IDisposable

        ''' <summary>
        ''' Defines the stream type to retrieve
        ''' </summary>
        ''' <remarks></remarks>
        Public Enum StreamType As Byte
            Flash
            EEprom
            Consult
            Data
        End Enum

        Friend Enum UsbMode As Byte
            Normal
            Bootloader
        End Enum

        ' Private Info/Data holders
        Private mUsbHandle As Integer = 0
        Private mUsbInformation As New UsbBikiromInformation()
        Private m_Baud As UInt32 = 500000
        Private m_MaxRxPacket As UInteger = 186
        Private m_MaxTxPacket As UInteger = 1054  '1054
        Private m_Timeout As UInt16 = 500
        Private mUsbDriverVersion As UInt32 = 0
        Private mUsbLibraryVersion As UInt32 = 0
        Private mBoardVersion As UsbBikiromInformation._BoardVersion = UsbBikiromInformation._BoardVersion.BikiRomUSBV1
        Private mSerialNumber As String = ""
        Private mUsbMode As UsbMode = UsbMode.Normal

#Region "Events and Delegates"
        Public Delegate Sub UsbExceptionEvent(ByVal sender As Object, ByVal e As USB_exceptions)

        Public Event CommunicationExceptionEventHandler As System.EventHandler(Of UsbCommunicationStatusEventArgs)
        Public Event CommunicationStatusEventHandler As System.EventHandler(Of UsbCommunicationStatusEventArgs)
        Public Event CommunicationEstablished As System.EventHandler
        Friend Event StreamDataEventHandler As System.EventHandler(Of UsbDataEventArguments)
        Friend Event EEPromDataEventHandler As System.EventHandler(Of UsbDataEventArguments)
        Friend Event FlashDataEventHandler As System.EventHandler(Of UsbDataEventArguments)
        Friend Event ConsultDataEventHandler As System.EventHandler(Of UsbDataEventArguments)
#End Region

#Region "USB Recieve Buffer Queues, Complete Frames per item."
        Friend m_UsbFlashDataBuffer As Comm.Comm_Frame
        Friend m_UsbEEpromDataBuffer As Comm.Comm_Frame
        Friend m_UsbLastCmdStatusBuffer As Comm.Comm_Frame
        Friend m_UsbLastCmdStatusBfr As New Queue
        Friend m_UsbConsultPassBuffer As Byte()
        Friend m_usbConsultPassArray As New MemoryStream
        Friend m_UsbConsultIntegratedBuffer As Comm.Comm_Frame
        Friend m_UsbGeneralSpecificBuffer As Comm.Comm_Frame
        Friend m_UsbRandomBytesBuffer As Comm.Comm_Frame
        Friend m_UsbDataLogBuffer As Comm.Comm_Frame

        ' Events for data recieval
        Friend m_usbConnectionCheck As New AutoResetEvent(False)
        Friend m_UsbFlashDataEvent As New AutoResetEvent(False)
        Friend m_UsbFlashDataEvent2 As New AutoResetEvent(False)
        Friend m_UsbEEpromDataEvent As New AutoResetEvent(False)
        Friend m_UsbEEpromDataEvent2 As New AutoResetEvent(False)
        Friend m_UsbLastCmdStatusEvent As New AutoResetEvent(False)
        Friend m_UsbCRCFailedEvent As New AutoResetEvent(False)
        Friend m_UsbHeadersFailedEvent As New AutoResetEvent(False)
        Friend m_UsbConsultEvent As New AutoResetEvent(False)
        Friend m_UsbConsultEvent2 As New AutoResetEvent(False)
        Friend m_UsbStreamEvent As New AutoResetEvent(False)
        Friend m_UsbStreamEvent2 As New AutoResetEvent(False)
        Friend m_UsbDataLogEvent As New AutoResetEvent(False)
        Friend m_UsbGeneralSpecificEvent As New AutoResetEvent(False)
        Friend m_ShutdownThreads As New Threading.ManualResetEvent(False)
#End Region

        ' Timer Initialisation events
        Friend WithEvents m_OnlineTimer As New System.Timers.Timer

        Private mCommunicationInitialised As Boolean = False
        Shared mCummunicationStreamMutex As New Mutex(False)

        Private mCurrentStream As Comm.BikiStream = Nothing

        Sub New(ByVal InitReciever As Boolean)
            Dim usbReturn As BK_return = BK_return.BK_FAILED_INIT

            '            dim blah as New threading.Th

            m_OnlineTimer.Interval = 500
            m_OnlineTimer.AutoReset = False
            m_OnlineTimer.Start()

            InitiliseSettings()

            Me.InitialiseReciever()

            Debug.Print("Rcv-Handler: USB Handler Created!")
        End Sub

        Sub InitiliseSettings()
            m_MaxRxPacket = 186 '248
            m_MaxTxPacket = 1054
            m_Timeout = 500
            mUsbDriverVersion = 0
            mUsbLibraryVersion = 0
            mSerialNumber = ""
            mBoardVersion = UsbBikiromInformation._BoardVersion.BikiRomUSBV1
        End Sub

#Region "       Functions"

        ''' <summary>
        ''' This routine checks for the existance of a USB connection, and continualy attemps to gain connection to it.
        ''' It will also check if it has gone offline and error appropriate messages via the event handlers.
        ''' </summary>
        ''' <param name="sender"></param>
        ''' <param name="e"></param>
        ''' <remarks></remarks>
        Private Sub OnlineTimer_Tick(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs) Handles m_OnlineTimer.Elapsed
            m_usbConnectionCheck.Set()

        End Sub
        Private Sub ConnectionCheck()
            Dim bDriverWarned As Boolean = False
            m_OnlineTimer.Stop()
            If Me.mUsbMode = UsbMode.Normal Then
                'timer.Enabled = False
                ' determine if we are conncetd
                If Not Me.IsConnected Then
                    If Me.Open() = True Then
                        If bDriverWarned = False AndAlso (Not CheckLibraryVersion() Or Not CheckDriverVersions()) Then
                            bDriverWarned = True
                            RaiseEvent CommunicationExceptionEventHandler(Me, New UsbCommunicationStatusEventArgs("BikiROM USB Driver Version Requires Updating. Install latest BikiUSB Device Driver from the Installation Directory", True, False))
                        End If
                        ' Reset the device and establish connection
                        Me.ResetDevice()

                        Thread.Sleep(10)
                        ClearEvents()
                    ElseIf Not CheckDriverVersions() Then
                        bDriverWarned = True
                        RaiseEvent CommunicationExceptionEventHandler(Me, New UsbCommunicationStatusEventArgs("BikiROM USB Driver Version Requires Updating. Install latest BikiUSB Device Driver from the Installation Directory", False, False))
                    Else

                        RaiseEvent CommunicationStatusEventHandler(Me, New UsbCommunicationStatusEventArgs("BikiUSB Device Not Found", False, False))
                    End If
                End If

                ' Check if conncted after open request
                If Me.IsConnected Then
                    If Not Me.Initialised Then
                        RaiseEvent CommunicationStatusEventHandler(Me, New UsbCommunicationStatusEventArgs("BikiUSB USB .. Attempting to init comms", True, False))
                        Debug.Print(String.Format("Handle is Started {0} tid {1}", Me.Handle, Threading.Thread.CurrentThread.ManagedThreadId))
                        If Not Me.Initialise() Then
                            If Me.Handle = 0 Then
                                Debug.Print("Rcv-Timer: Handle is zero!")
                            Else
                                If m_UsbTxRxMutex.WaitOne() Then
                                    If FT_ResetDevice(Me.Handle) <> FT_return.FT_OK Then
                                        Me.Close()
                                        RaiseEvent CommunicationStatusEventHandler(Me, New UsbCommunicationStatusEventArgs("BikiUSB USB Chip Reset Failed", False, False))
                                    Else
                                        RaiseEvent CommunicationStatusEventHandler(Me, New UsbCommunicationStatusEventArgs("BikiUSB USB Chip Reset ... Attempting initialise ", True, False))
                                    End If
                                    m_UsbTxRxMutex.ReleaseMutex()
                                End If

                            End If
                        End If
                        Debug.Print(String.Format("Handle is Finished {0} tid {1}", Me.Handle, Threading.Thread.CurrentThread.ManagedThreadId))
                    Else

                        Dim time As Byte
                        Select Case FT_GetLatencyTimer(mUsbHandle, time)

                            '    Select Case FT_SetEventNotification(mUsbHandle, FT_Events.FT_EVENT_RXCHAR, m_UsbRxEvent.SafeWaitHandle.DangerousGetHandle)
                            'Case FT_return.FT_DEVICE_NOT_FOUND, FT_return.FT_DEVICE_NOT_OPENED, _
                            '    FT_return.FT_DEVICE_NOT_OPENED_FOR_ERASE, FT_return.FT_DEVICE_NOT_OPENED_FOR_WRITE, _
                            '    FT_return.FT_INVALID_HANDLE
                            '    ' If the drivers cannot be commed with. Close and un-init!

                            'Case FT_return.FT_FAILED_TO_WRITE_DEVICE, FT_return.FT_INSUFFICIENT_RESOURCES, _
                            '    FT_return.FT_IO_ERROR, FT_return.FT_IO_FAILED, _
                            '    FT_return.FT_IO_TIMEOUT, FT_return.FT_OTHER_ERROR
                            '    ' If the device just can't be commed with.. just un-initialise it

                            '    Me.mCommunicationInitialised = False

                            Case FT_return.FT_OK

                                ' All communications are A OK!

                            Case Else
                                '  If FT_CyclePort(Me.mUsbHandle) <> FT_return.FT_OK Then

                                Me.Close()
                                Me.mCommunicationInitialised = False
                                If Me.ConnectFirstDevice(Me.mUsbHandle) <> BK_return.BK_OK Then

                                    Debug.WriteLine("Communication Dropped, Unitnitialising")
                                    RaiseEvent CommunicationStatusEventHandler(Me, New UsbCommunicationStatusEventArgs("Communication has dropped out", Me.IsConnected, Me.Initialised))
                                Else
                                    Initialise()

                                End If
                                ' Throw up an event!
                                ' End If

                        End Select


                    End If
                End If
            End If
            If Not Me.disposedValue Then
                m_OnlineTimer.Start()
                'timer.Enabled = True
            End If
        End Sub

        ''' <summary>
        ''' Closes the current communication handler
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub Close()
            '  CloseRecievers()
            Me.mCommunicationInitialised = False
            FT_Close(Me.mUsbHandle)
            Me.mUsbHandle = 0
            Debug.Print("rcv-Handler: FT_Close Called")
            'Me.m_OnlineTimer.Stop()
        End Sub

        Private Sub CloseRecievers()
            Debug.Print("Setting up for closing reciever")
            m_ShutdownThreads.Set()
            If Not IsNothing(m_CommThread) AndAlso m_CommThread.IsAlive Then
                m_CommThread.Join(1000)
                m_CommThread = Nothing
            End If
            If Not IsNothing(m_EventThread) AndAlso m_EventThread.IsAlive Then
                m_EventThread.Join(1000)
                m_EventThread = Nothing
            End If
            If Not IsNothing(m_ConnThread) AndAlso m_ConnThread.IsAlive Then
                m_ConnThread.Join(1000)
                m_ConnThread = Nothing
            End If
        End Sub

        ''' <summary>
        ''' Opens the First avaialbe Bikirom Device
        ''' </summary>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Function Open() As Boolean
            If mUsbHandle = 0 Then
                If Me.ConnectFirstDevice(mUsbHandle) = BK_return.BK_OK Then
                    Me.m_OnlineTimer.Start()
                    Return True
                Else
                    Return False
                End If
            Else
                Me.Close()
                Return Me.Open()
            End If
        End Function

        Friend Function Open(ByVal Mode As Comm.UsbCommunicationHandle.UsbMode) As Boolean
            Me.mUsbMode = Mode
            Return Me.Open
        End Function

        ''' <summary>
        ''' Initialises the Reciever
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub InitialiseReciever()
            ' signal no shutdown
            m_ShutdownThreads.Reset()

            If IsNothing(m_ConnThread) Or (Not IsNothing(m_ConnThread) AndAlso Not m_ConnThread.IsAlive) Then 'Or (Not IsNothing(m_CommThread) AndAlso Not m_CommThread.IsAlive) Then
                m_ConnThread = New Thread(AddressOf Me.ConnectionThreadExecute)
                m_ConnThread.Name = "BikiRom USB Connection Thread for: 0x" & Hex(mUsbHandle)
                Debug.Print("Comm-Init: Connection Thread Initialised")
                m_ConnThread.Start()
            Else
                Debug.Print("Comm-Init: Connection Thread already initiailised")
            End If



            If IsNothing(m_CommThread) Or (Not IsNothing(m_CommThread) AndAlso Not m_CommThread.IsAlive) Then 'Or (Not IsNothing(m_CommThread) AndAlso Not m_CommThread.IsAlive) Then
                m_CommThread = New Thread(AddressOf Me.RecieveThreadExecute)
                m_CommThread.Name = "BikiRom USB Comm Thread for: 0x" & Hex(mUsbHandle)
                'm_CommThread.IsBackground = True
                Debug.Print("Comm-Init: Comm Thread Initialised")
                m_CommThread.Start()
            Else
                Debug.Print("Comm-Init: Comm Thread already initiailised")
            End If

            If IsNothing(m_EventThread) Or (Not IsNothing(m_EventThread) AndAlso Not m_EventThread.IsAlive) Then
                Debug.Print("Comm-Init: Event thread started")
                m_EventThread = New Thread(AddressOf Me.EventThreadExecute)
                m_EventThread.Name = "BikiRom USB Event Thread for: 0x" & Hex(mUsbHandle)
                '  m_EventThread.IsBackground = True
                If Not m_EventThread.IsAlive Then
                    m_EventThread.Start()
                End If
            Else
                Debug.Print("Comm-Init: Event thread Already started")
            End If
        End Sub

        ''' <summary>
        ''' Performs a check to see if the Bootup is OK
        ''' </summary>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Function Initialise() As Boolean
            Dim bStatus As Boolean = True

            If Not Me.Initialised Then
                Try
                    ' InitialiseReciever()
                    Debug.Print(String.Format("Initialising {0} at {1}", Threading.Thread.CurrentThread.ManagedThreadId, Now))
                    Dim f_Frame As Comm.Comm_Frame

                    Me.Timeout = 1000

                    ' Reset BikiRom
                    Me.ResetDevice()

                    ' Wait for board bootup command
                    f_Frame = New Comm.Comm_Frame(Comm_Frame.BikiFrameType.ID_LAST_COMMAND_STATUS, , , , Comm_Frame.BikiFrameType.ID_LAST_COMMAND_STATUS)
                    If SendFrame(f_Frame, , False) = Comm_Frame.BikiFrameResponse.CMD_BOOT Then
                        Debug.Print("Comm-Init{1}: Bootup recieved")
                    ElseIf m_UsbRx.Count > 0 Then
                        If m_UsbRx(0) = &HBB Or m_UsbRx(0) = &HB1 Or m_UsbRx(0) = &HB9 Then
                            RaiseEvent CommunicationStatusEventHandler(Me, New UsbCommunicationStatusEventArgs("Old Firmware Detected. Please Update Firmare", Me.IsConnected, False))
                        End If
                    Else
                        Debug.Print("Comm-Init{1}: Bootup not recieved")
                        bStatus = False
                    End If

                    Thread.Sleep(400)

                    If bStatus Then
                        If Not mUsbInformation.GetBikiromInfo(Me) Then
                            Debug.Print("Comm-Init{2}: Failed to get info")
                            bStatus = False
                        Else
                            Debug.Print("Comm-Init{2}: Got Info OK at " & Now)
                            f_Frame = New Comm.Comm_Frame(Comm.Comm_Frame.BikiFrameType.ID_CONSULT_INTEGRATED, , Comm.Comm_Frame.BikiFrameAction.CMD_STOP)
                            If SendFrame(f_Frame) = Comm_Frame.BikiFrameResponse.CMD_OK Then
                                RaiseEvent CommunicationEstablished(Me, New System.EventArgs)
                                RaiseEvent CommunicationStatusEventHandler(Me, New UsbCommunicationStatusEventArgs("Communication Established", Me.IsConnected, Me.Initialised))
                            Else
                                bStatus = False
                            End If
                        End If
                    End If
                Catch ex As Comm_Exceptions
                    bStatus = False
                End Try

                Me.mCommunicationInitialised = bStatus
            Else
                bStatus = True
                Debug.Print(String.Format("Comm-Init: Already Initialised {0} at {1}", Threading.Thread.CurrentThread.ManagedThreadId, Now))
            End If
            Return bStatus
        End Function

        ''' <summary>
        ''' Connects to the first available device. Not specific to a device
        ''' </summary>
        ''' <remarks></remarks>
        Private Function ConnectFirstDevice(ByRef Handle As Integer) As BK_return
            Dim bStatus As Boolean = True
            Dim lngNumDevs As UInt32
            Dim foundDevices As New ArrayList()

            ' This is a Very important loading, if the DLL is not found.. then we're basicaly fucked :)
            Try

                If bStatus And FT_CreateDeviceInfoList(lngNumDevs) <> FT_return.FT_OK AndAlso lngNumDevs > 0 Then
                    bStatus = False
                Else
                    Dim devices(lngNumDevs - 1) As FT_DEVICE_INFO

                    For nIndex As Integer = 0 To lngNumDevs - 1
                        ReDim devices(nIndex).pchSerial(16)
                        ReDim devices(nIndex).pchDesc(100)
                        FT_GetDeviceInfoDetail(nIndex, devices(nIndex).nFlags, devices(nIndex).nType, devices(nIndex).nID, devices(nIndex).nLocid, devices(nIndex).pchSerial, devices(nIndex).pchDesc, devices(nIndex).nHandle)
                        devices(nIndex).SerialNumber = cv_StringFromBytes(devices(nIndex).pchSerial)
                        devices(nIndex).Description = cv_StringFromBytes(devices(nIndex).pchDesc)

                        Console.WriteLine("Device Found: ID:{0}, FLAGS:{1}, LOCID{2}, SERIAL:{3}, DESC:{4}", devices(nIndex).nID, Hex(devices(nIndex).nFlags), devices(nIndex).nLocid, devices(nIndex).SerialNumber, devices(nIndex).Description)

                        If (devices(nIndex).nType = FT_DEVICE.FT_DEVICE_232BM _
                            Or devices(nIndex).nType = FT_DEVICE.FT_DEVICE_232R) _
                        AndAlso (devices(nIndex).Description.ToLower.Contains("bikirom") _
                            Or devices(nIndex).Description.ToLower.Contains("bikir0m") _
                            Or devices(nIndex).Description.ToLower.Contains("bikiusb")) _
                        AndAlso (devices(nIndex).nFlags And &H1) = 0 Then
                            foundDevices.Add(devices(nIndex))
                        End If
                    Next
                End If

                If bStatus And foundDevices.Count > 0 Then

                    If foundDevices.Count >= 2 Then
                        Dim question As String = String.Format("More than one BikiRom Device has been found. " & Chr(13) & _
                                                                "Enter the number of the device (1-{0}) " & Chr(13), foundDevices.Count)
                        For count As Integer = 1 To foundDevices.Count
                            question &= String.Format("{0}: {1}({2})" & Chr(13), count, CType(foundDevices(count - 1), FT_DEVICE_INFO).Description, CType(foundDevices(count - 1), FT_DEVICE_INFO).SerialNumber)
                        Next

                        Dim response As String = InputBox(question, "More than One BikiRom USB Deivce Found", "1")

                        If Val(response) <= foundDevices.Count And Val(response) > 0 Then
                            If FT_OpenEx(CType(foundDevices(Val(response) - 1), FT_DEVICE_INFO).SerialNumber, FT_Open.FT_OPEN_BY_SERIAL_NUMBER, Handle) <> FT_return.FT_OK Then
                                bStatus = False
                            End If
                        End If
                    Else
                        If FT_OpenEx(CType(foundDevices(0), FT_DEVICE_INFO).SerialNumber, FT_Open.FT_OPEN_BY_SERIAL_NUMBER, Handle) <> FT_return.FT_OK Then
                            bStatus = False
                        End If
                    End If

                ElseIf bStatus Then

                    If FT_OpenByIndex(0, Handle) <> FT_return.FT_OK Then
                        bStatus = False
                    End If

                End If

                If bStatus Then
                    Dim f_Type, f_ID As Integer
                    Dim f_Serial As String = ""
                    f_Serial = f_Serial.PadLeft(100)
                    Dim f_Desc As String = ""
                    f_Desc = f_Desc.PadLeft(100)
                    FT_GetDeviceInfo(Handle, f_Type, f_ID, f_Serial, f_Desc, Nothing)

                    Dim f_baud As UInt16

                    If f_Type = 5 Then
                        mBoardVersion = UsbBikiromInformation._BoardVersion.BikiRomUSBV3
                        mSerialNumber = f_ID

                        m_Baud = 375000
                    Else
                        mBoardVersion = UsbBikiromInformation._BoardVersion.BikiRomUSBV2
                        mSerialNumber = f_Serial
                        FT_ClrRts(Handle)

                        GetUsbVariable(Biki_USBvars.UV_Baud, f_baud)
                        If f_baud = 250 Or f_baud = 500 Or f_baud = 375 Then
                            m_Baud = f_baud * 1000
                        Else
                            m_Baud = 500000
                        End If
                    End If
                End If

                If bStatus AndAlso FT_SetBaudRate(Handle, m_Baud) <> FT_return.FT_OK Then
                    bStatus = False
                Else
                    Console.WriteLine("BikiRom_Connect: Baud = {0:N}", m_Baud)
                End If

                If bStatus Then
                    Dim f_OverHeadRx As Integer = MaxRxPacket \ 62
                    f_OverHeadRx = (((MaxRxPacket Mod 62) + MaxRxPacket) \ 62) * 64

                    Dim f_OverHeadTx As Integer = MaxTxPacket \ 62
                    f_OverHeadTx = (((MaxTxPacket Mod 62) + MaxTxPacket) \ 62) * 64

                    If FT_SetUSBParameters(Handle, f_OverHeadRx, f_OverHeadTx) <> FT_return.FT_OK Then
                        bStatus = False
                    End If
                End If

                If bStatus AndAlso FT_SetDataCharacteristics(Handle, FT_Bits.FT_BITS_8, FT_Stop_Bits.FT_STOP_BITS_1, FT_Parity.FT_PARITY_NONE) <> FT_return.FT_OK Then
                    bStatus = False
                End If

                If bStatus Then
                    If mBoardVersion = UsbBikiromInformation._BoardVersion.BikiRomUSBV3 And mUsbMode = UsbMode.Normal Then
                        If FT_SetFlowControl(Handle, FT_Flow.FT_FLOW_RTS_CTS, 0, 0) <> FT_return.FT_OK Then
                            bStatus = False
                        End If
                    Else
                        If FT_SetFlowControl(Handle, FT_Flow.FT_FLOW_NONE, 0, 0) <> FT_return.FT_OK Then
                            bStatus = False
                        End If
                    End If
                End If

                If bStatus AndAlso FT_SetBitMode(Handle, 0, 0) <> FT_return.FT_OK Then
                    bStatus = False
                End If

                If bStatus AndAlso FT_SetTimeouts(Handle, 1000, 1000) <> FT_return.FT_OK Then
                    bStatus = False
                End If

                If bStatus AndAlso FT_SetLatencyTimer(Handle, 2) <> FT_return.FT_OK Then
                    bStatus = False
                End If
                '  FT_SetEventNotification(Handle, FT_Events.FT_EVENT_RXCHAR, m_UsbRxEvent.SafeWaitHandle.DangerousGetHandle)

                If bStatus Then
                    Return BK_return.BK_OK
                Else
                    FT_Close(Handle)
                    Handle = 0
                    Return BK_return.BK_IO_ERROR_BIK
                End If

            Catch ex As DllNotFoundException
                Dim form As New frmInformation("USB Driver Not Found", _
                "Unable to find the BikiRom USB Device Drivers. Please re-install the USB Drivers from the installation folder. Requires > V2.4.5 27/6/07" & Chr(13) & _
                "Note: BikiSoft Version 4.0.0 onwards requires the latest USB Drivers to be installed. You can find these inside the installation folder" & _
                " which is usualy 'C:\Program Files\Bikirom\BikiSoftV4\USB Drivers\", _
                ex.Message, _
                MsgBoxStyle.Information)

                If Handle <> 0 Then
                    FT_Close(Handle)
                    Handle = 0
                End If

                form.ShowDialog()

                End
            End Try
        End Function

        ''' <summary>
        ''' Checks the USB Driver Version. Returns false if driver not found or
        ''' incorrect version
        ''' </summary>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Private Function CheckDriverVersions() As Boolean
            Dim dwVersion As UInt32
            Dim bStatus As Boolean = True
            Try
                If FT_GetLibraryVersion(dwVersion) = FT_return.FT_OK Then
                    Debug.Print("Driver Version is {0}", Hex(dwVersion))

                    If dwVersion < My.Settings.USBDriverLatestVersion And dwVersion <> Me.mUsbDriverVersion Then
                        bStatus = False
                    End If

                    Me.mUsbDriverVersion = dwVersion
                Else
                    bStatus = False
                End If
            Catch ex As DllNotFoundException
                bStatus = False
            End Try

            Return bStatus
        End Function

        Private Function CheckLibraryVersion() As Boolean
            Dim dwVersion As UInt32
            Dim bStatus As Boolean = True
            Try
                If FT_GetDriverVersion(Me.mUsbHandle, dwVersion) = FT_return.FT_OK Then
                    Debug.Print("Library Version is {0}", Hex(dwVersion))

                    If dwVersion < My.Settings.USBLibraryLatestVersion And dwVersion <> Me.mUsbLibraryVersion Then
                        bStatus = False
                    End If

                    Me.mUsbLibraryVersion = dwVersion
                Else
                    bStatus = False
                End If
            Catch ex As DllNotFoundException
                bStatus = False
            End Try

            Return bStatus
        End Function

        ''' <summary>
        ''' Resets the Device into initial operation state
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub ResetDevice()
            FT_ClrRts(mUsbHandle)
            Threading.Thread.Sleep(20)
            FT_SetDtr(mUsbHandle)
            Threading.Thread.Sleep(20)
            FT_ClrDtr(mUsbHandle)
            '  Threading.Thread.Sleep(100)

            Me.mCommunicationInitialised = False
            mUsbMode = UsbMode.Normal

            ' Initialise()
        End Sub

        ''' <summary>
        ''' Resets the Device into Bootloader mode
        ''' </summary>
        ''' <remarks></remarks>
        Friend Sub ResetForBootMode()
            FT_SetRts(mUsbHandle)
            Threading.Thread.Sleep(20)
            FT_SetDtr(mUsbHandle)
            Threading.Thread.Sleep(100)
            FT_ClrDtr(mUsbHandle)

            mUsbMode = UsbMode.Bootloader
        End Sub

        Friend Sub ResetForBootModeAlternate()
            FT_ClrRts(mUsbHandle)
            Threading.Thread.Sleep(20)
            FT_SetDtr(mUsbHandle)
            Threading.Thread.Sleep(20)
            FT_ClrDtr(mUsbHandle)

            mUsbMode = UsbMode.Bootloader
        End Sub

        Public Sub Flush()
            FT_Purge(mUsbHandle, FT_Purg.FT_PURGE_RX + FT_Purg.FT_PURGE_TX)
            ClearBuffers()
        End Sub

        Public Function GetStream(ByVal StreamType As StreamType) As Comm.BikiStream

            If Not IsNothing(mCurrentStream) Then
                mCurrentStream.Dispose()
                mCurrentStream = Nothing
            End If

            Select Case StreamType
                Case UsbCommunicationHandle.StreamType.Consult
                    Return New Comm.ConsultStream(mCummunicationStreamMutex, Me)
                Case UsbCommunicationHandle.StreamType.Data
                    Return New Comm.DataStream(mCummunicationStreamMutex, Me)
                Case UsbCommunicationHandle.StreamType.EEprom
                    Return New Comm.EEpromStream(mCummunicationStreamMutex, Me)
                Case UsbCommunicationHandle.StreamType.Flash
                    Return New Comm.FlashStream(mCummunicationStreamMutex, Me)
                Case Else
                    Return Nothing
            End Select
        End Function

        Public Sub ReleaseStream(ByVal Stream As Comm.BikiStream)
            If Stream Is mCurrentStream Then
                mCurrentStream.Dispose()
                mCurrentStream = Nothing
            End If
        End Sub

        ''' <summary>
        ''' This function should perform a periodic check of the current link status with
        ''' the bikirom.
        ''' </summary>
        ''' <remarks></remarks>
        Private Sub HealthCheckDevice()
            FT_ClrRts(mUsbHandle)
            Threading.Thread.Sleep(20)
            FT_SetDtr(mUsbHandle)
            Threading.Thread.Sleep(20)
            FT_ClrDtr(mUsbHandle)
            Threading.Thread.Sleep(100)
        End Sub

        ''' <summary>
        ''' Clears all the current event signals. This should be called before
        ''' doing any large operations as previous operations may have left
        ''' some items flagged
        ''' </summary>
        ''' <remarks></remarks>
        Private Sub ClearEvents()
            m_UsbFlashDataEvent.Reset()
            m_UsbLastCmdStatusEvent.Reset()
            m_UsbEEpromDataEvent.Reset()
            m_UsbCRCFailedEvent.Reset()
            m_UsbConsultEvent.Reset()
            m_UsbHeadersFailedEvent.Reset()
            m_UsbStreamEvent.Reset()
            m_UsbGeneralSpecificEvent.Reset()
        End Sub

        ''' <summary>
        ''' Performs a flush of all buffers. 
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub ClearBuffers()
            m_UsbFlashDataBuffer = Nothing
            m_UsbEEpromDataBuffer = Nothing
            m_UsbLastCmdStatusBuffer = Nothing
            m_UsbConsultIntegratedBuffer = Nothing
            m_UsbGeneralSpecificBuffer = Nothing
            m_UsbRandomBytesBuffer = Nothing
            m_UsbConsultPassBuffer = Nothing
        End Sub

        ''' <summary>
        ''' Functions below read data from the USB FT232's EEPROM space and write to it in a quick and easy fassion
        ''' </summary>
        ''' <remarks>These functions Assume that you already have a USB connection to the device</remarks>
        Friend Function GetUsbVariable(ByVal var As Biki_USBvars, ByRef oShort As UInt16) As Boolean
            If Me.IsConnected Then
                Dim f_size As Integer
                If FT_EE_UASize(mUsbHandle, f_size) = FT_return.FT_OK Then
                    If var + 1 >= f_size Then Return False : Exit Function
                    Dim f_bytes(f_size - 1) As Byte
                    Dim f_read As Integer
                    If FT_EE_UARead(mUsbHandle, f_bytes, f_size, f_read) = FT_return.FT_OK Then
                        oShort = MAKEWORD(f_bytes(var + 1), f_bytes(var))
                        Return True
                    Else : Return False
                    End If
                Else : Return False
                End If
            End If
            Return False
        End Function
        Friend Function GetUsbVariable(ByVal var As Biki_USBvars, ByRef oByte As Byte) As Boolean
            If Me.Initialised Then
                Dim f_size As Integer
                If FT_EE_UASize(mUsbHandle, f_size) = FT_return.FT_OK Then
                    If var + 1 >= f_size Then Return False : Exit Function
                    Dim f_bytes(f_size - 1) As Byte
                    Dim f_read As Integer
                    If FT_EE_UARead(mUsbHandle, f_bytes, f_size, f_read) = FT_return.FT_OK Then
                        oByte = f_bytes(var)
                        Return True
                    Else : Return False
                    End If
                Else : Return False
                End If
            End If
            Return False
        End Function
        Friend Function GetUsbVariable(ByVal var As Biki_USBvars, ByRef oIntValue As UInt32) As Boolean
            If Me.Initialised Then
                Dim f_size As Integer
                If FT_EE_UASize(mUsbHandle, f_size) = FT_return.FT_OK Then
                    If var + 1 >= f_size Then Return False : Exit Function
                    Dim f_bytes(f_size - 1) As Byte
                    Dim f_read As Integer
                    If FT_EE_UARead(mUsbHandle, f_bytes, f_size, f_read) = FT_return.FT_OK Then
                        Select Case var
                            Case Biki_USBvars.UV_Baud
                                oIntValue = MAKEWORD(f_bytes(var + 1), f_bytes(var))
                            Case Biki_USBvars.UV_EcuFLASH_CRC To Biki_USBvars.UV_EcuFLASH_CRC_MAP_3, Biki_USBvars.UV_BikPROG
                                oIntValue = makeLong(f_bytes(var), f_bytes(var + 1), f_bytes(var + 2), f_bytes(var + 3))
                        End Select
                        Return True
                    Else : Return False
                    End If
                Else : Return False
                End If
            End If
            Return False
        End Function
        Friend Function SetUsbVariable(ByVal var As Biki_USBvars, ByVal sIntValue As UInt32) As Boolean
            If Me.Initialised Then
                Dim f_size As Integer
                If FT_EE_UASize(mUsbHandle, f_size) = FT_return.FT_OK Then
                    If var + 1 >= f_size Then Return False : Exit Function
                    Dim f_bytes(25) As Byte
                    Dim f_read As Integer
                    If FT_EE_UARead(mUsbHandle, f_bytes, f_size, f_read) = FT_return.FT_OK Then
                        Select Case var
                            Case Biki_USBvars.UV_FirmWare
                                f_bytes(var) = sIntValue And &HFF
                            Case Biki_USBvars.UV_Baud, Biki_USBvars.UV_BikSync
                                f_bytes(var + 1) = LOBYTE(sIntValue)
                                f_bytes(var) = HIBYTE(sIntValue)
                            Case Biki_USBvars.UV_EcuFLASH_CRC To Biki_USBvars.UV_EcuFLASH_CRC_MAP_3, Biki_USBvars.UV_BikPROG
                                f_bytes(var) = HIBYTE(hiInt(sIntValue))
                                f_bytes(var + 1) = LOBYTE(hiInt(sIntValue))
                                f_bytes(var + 2) = HIBYTE(loInt(sIntValue))
                                f_bytes(var + 3) = LOBYTE(loInt(sIntValue))
                        End Select
                        If FT_EE_UAWrite(mUsbHandle, f_bytes, f_size) = FT_return.FT_OK Then Return True Else Return False
                    Else
                        Return False
                    End If
                Else
                    Return False
                End If
            End If
            Return False
        End Function

#End Region

#Region "       Properties"
        ''' <summary>
        ''' Returns true if the current class has initialised communication
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public ReadOnly Property Initialised() As Boolean
            Get
                Return mCommunicationInitialised
            End Get
        End Property

        ''' <summary>
        ''' Returns true if the current handler has connected to a usb device
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public ReadOnly Property IsConnected() As Boolean
            Get
                If Me.mUsbHandle <> 0 Then
                    Return True
                Else
                    Return False
                End If
            End Get
        End Property

        ''' <summary>
        ''' Returns the current USB information
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public ReadOnly Property UsbInformation() As UsbBikiromInformation
            Get
                Return mUsbInformation
            End Get
        End Property

        ''' <summary>
        ''' Gets the current USB Handle
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public ReadOnly Property Handle() As Integer
            Get
                Return mUsbHandle
            End Get
        End Property

        ''' <summary>
        ''' Specifies the timeout for the current operations
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Property Timeout() As Integer
            Get
                Return m_Timeout
            End Get
            Set(ByVal value As Integer)
                If value > 0 Then
                    m_Timeout = value
                    ' If m_UsbTxRxMutex.WaitOne() Then
                    FT_SetTimeouts(mUsbHandle, Me.Timeout, Me.Timeout)
                    'm_UsbTxRxMutex.ReleaseMutex()
                    '   End If
                End If
            End Set
        End Property

        ''' <summary>
        ''' Retrieves the maximum Recieve packet size
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public ReadOnly Property MaxRxPacket() As Integer
            Get
                Return Me.m_MaxRxPacket
            End Get
        End Property

        ''' <summary>
        ''' Retrieves the maximum Send packet size
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public ReadOnly Property MaxTxPacket() As Integer
            Get
                Return Me.m_MaxTxPacket
            End Get
        End Property

        ''' <summary>
        ''' Retrieves the current Baud Rate
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Friend ReadOnly Property Baud() As UInt32
            Get
                Return m_Baud
            End Get
        End Property

        ''' <summary>
        ''' Returns the current library version
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public ReadOnly Property CurrentLibraryVersion() As UInt32
            Get
                Return Me.mUsbLibraryVersion
            End Get
        End Property

        ''' <summary>
        ''' Reutrns the current Driver Version
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public ReadOnly Property CurrentDriverVersion() As UInt32
            Get
                Return mUsbDriverVersion
            End Get
        End Property

        ''' <summary>
        ''' Retrieves the BikiRom Board Version
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public ReadOnly Property BoardVersion() As UsbBikiromInformation._BoardVersion
            Get
                Return Me.mBoardVersion
            End Get
        End Property

        ''' <summary>
        ''' Retrieves the BikiRom Board Serial Number
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public ReadOnly Property SerialNumber() As String
            Get
                Return mSerialNumber
            End Get
        End Property
#End Region

#Region "Thread Execution Rx Handler"
        ' Communication Mutex
        Shared m_UsbTxRxMutex As New Mutex(False, "RxTxComm")
        ' Usb RX Event used to hook into the DLL's
        Shared m_UsbRxEvent As New Threading.EventWaitHandle(False, EventResetMode.AutoReset)
        Shared m_UsbRxTimerEvent As New Threading.EventWaitHandle(False, EventResetMode.AutoReset)
        Private WithEvents m_usbRxTimer As New System.Timers.Timer(1)
        'Private m_UsbRxEvent As New AutoResetEvent(False)
        ' Communication Thread used for recieveing and notifying about data recieval
        Shared m_CommThread As Thread = Nothing
        Shared m_ConnThread As Thread = Nothing
        Shared m_EventThread As Thread = Nothing
        ' Global status variable for this class, determines which byte is currently being seeked out
        Private m_RxStatus As UInt16 = 0
        ' Global Bytes Excepted Variable.
        Private m_RxBytes As UInt16 = 0
        ' USB Primary Recieve Buffer and threads
        Friend m_UsbRx As New ArrayList(4000)

        Sub m_UsbRxTimer_Elapsed(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs) Handles m_usbRxTimer.Elapsed
            m_UsbRxTimerEvent.Set()
        End Sub

        ''' <summary>
        ''' Function to be called ONLY as a thread!
        ''' </summary>
        ''' <remarks>Thread Only Function</remarks>
        Sub EventThreadExecute()
            Dim WaitHandles() As WaitHandle = New WaitHandle() {m_UsbFlashDataEvent2, _
                                                                m_UsbEEpromDataEvent2, _
                                                                m_UsbStreamEvent2, _
                                                                m_UsbConsultEvent2, _
                                                                m_ShutdownThreads}
            Do
                Try
                    Select Case WaitHandle.WaitAny(WaitHandles, -1, False)
                        Case 0
                            RaiseEvent FlashDataEventHandler(Me, New UsbDataEventArguments(m_UsbFlashDataBuffer))
                        Case 1
                            RaiseEvent EEPromDataEventHandler(Me, New UsbDataEventArguments(m_UsbEEpromDataBuffer))
                        Case 2
                            RaiseEvent StreamDataEventHandler(Me, New UsbDataEventArguments(m_UsbConsultIntegratedBuffer))
                        Case 3
                            RaiseEvent ConsultDataEventHandler(Me, New UsbDataEventArguments(m_UsbConsultPassBuffer))
                        Case 4
                            Exit Do
                    End Select
                Catch ex As Exception
                    Debug.Print("Error in event!! BIG PROBLEM")
                End Try
            Loop
        End Sub

        Sub ConnectionThreadExecute()
            Dim WaitHandles() As WaitHandle = New WaitHandle() {m_usbConnectionCheck, _
                                                                m_ShutdownThreads}
            Do
                Try
                    Select Case WaitHandle.WaitAny(WaitHandles, -1, False)
                        Case 0
                            ConnectionCheck()
                        Case 1
                            Exit Do
                    End Select
                Catch ex As Exception
                    Debug.Print("Error in Connection!! BIG PROBLEM")
                End Try
            Loop
        End Sub

        ''' <summary>
        ''' Function to be called only as a thread
        ''' </summary>
        ''' <remarks></remarks>
        Sub RecieveThreadExecute()
            Dim i As UInt64
            Dim f_Rcv() As Byte
            Dim f_confirm As Boolean = True
            Dim uchBuffer(2048) As Byte
            Dim WaitHandles() As WaitHandle = New WaitHandle() {m_UsbRxEvent, m_ShutdownThreads, m_UsbRxTimerEvent}
            Dim nInt, nTx, nEv As Integer

            m_usbRxTimer.Start()

            Do
                Try
                    ' Block until read possible
                    'Threading.Thread.EndCriticalRegion()
                    nInt = WaitHandle.WaitAny(WaitHandles, -1, True)
                    Select Case (nInt)
                        Case WaitHandle.WaitTimeout, 2
                            If m_UsbTxRxMutex.WaitOne() Then
                                If FT_GetStatus(Me.Handle, nInt, nTx, nEv) = FT_return.FT_OK AndAlso nInt > 0 Then
                                    m_UsbTxRxMutex.ReleaseMutex()
                                    If nTx > 0 Then
                                        Debug.Print("Rcv-Thread: TxCount = " & nTx)
                                    End If
                                Else
                                    m_UsbTxRxMutex.ReleaseMutex()
                                    Continue Do
                                End If
                                'Debug.Print("Rcv-Thread: Manual setup of Read due to failed Event?")

                            End If
                        Case 0

                        Case 1
                            Exit Do

                        Case Else
                            Debug.Print(System.String.Format("Rcv-Thread: Recieved return of {0}", nInt))
                    End Select

                    m_UsbTxRxMutex.WaitOne()
                    ' Threading.Thread.BeginCriticalRegion()
                    f_Rcv = read_usb(nInt)
                    m_UsbTxRxMutex.ReleaseMutex()

                    If Not IsNothing(f_Rcv) AndAlso f_Rcv.Length > 0 Then
                        Debug.Print("Recieved: " & cv_HexFromBytes(f_Rcv))
                        i = 0
                        m_UsbRx.AddRange(f_Rcv)
retry:                  If m_RxStatus = 0 And m_UsbRx.Count >= 4 Then
                            For i = 0 To m_UsbRx.Count - 4
                                If m_UsbRx(i) = &HAA And _
                                 m_UsbRx(i + 1) = &HA5 And _
                                 m_UsbRx(i + 2) = &H1A And _
                                 (m_UsbRx(i + 3) = &H2A Or m_UsbRx(i + 3) = &HA Or m_UsbRx(i + 3) = &H70) _
                                 Then
                                    ' Headers Found!
                                    m_RxStatus = 4
                                    m_RxBytes = 0
                                    If i > 0 Then
                                        Dim crap(i) As Byte
                                        m_UsbRx.CopyTo(0, crap, 0, i)
                                        Debug.Print("Usb-Rcv: Crap Cleared'" & cv_HexFromBytes(crap) & "'")
                                        m_UsbRx.RemoveRange(0, i) ' clears out all the crap
                                    End If
                                    Exit For
                                End If
                            Next
                        End If
                        ' Header already in buffer and at begining, searching for the bytes
                        If m_RxStatus = 4 Then
                            If m_UsbRx.Count >= 6 Then
                                m_RxBytes = (CUShort(m_UsbRx(4)) * &H100US) + CUShort(m_UsbRx(5))
                                If m_RxBytes >= 2048 Then
                                    m_RxStatus = 0
                                    m_UsbRx.RemoveRange(0, 6)
                                    Debug.Print("Usb-Rcv: Too many bytes specified")
                                Else
                                    m_RxStatus = 6
                                End If
                            End If
                        End If
                        ' Headers and Bytes recieved, looking for final count in the stream now
                        If m_RxStatus = 6 Then
                            If m_UsbRx.Count >= (m_RxBytes + 10) Then
                                ' Headers and everything is ready..
                                ' Check if the Footer exists
                                If m_UsbRx(m_RxBytes + 9) = &H5A And _
                                   m_UsbRx(m_RxBytes + 8) = &H55 _
                                Then
                                    Dim f_Data(m_RxBytes + 9) As Byte
                                    m_UsbRx.CopyTo(0, f_Data, 0, m_RxBytes + 10)
                                    Dim f_Frame As New Comm.Comm_Frame(f_Data)
                                    If f_Frame.IsValid Then
                                        If m_UsbRx(3) = &H2A Or m_UsbRx(3) = &H70 Then
                                            Select Case CType(m_UsbRx(6), Comm.Comm_Frame.BikiFrameType)
                                                Case Comm_Frame.BikiFrameType.eMsgIdLogData
                                                    m_UsbDataLogBuffer = f_Frame
                                                    m_UsbDataLogEvent.Set()
                                                Case Comm.Comm_Frame.BikiFrameType.ID_CONSULT_INTEGRATED
                                                    m_UsbConsultIntegratedBuffer = f_Frame
                                                    m_UsbStreamEvent.Set()
                                                    m_UsbStreamEvent2.Set()
                                                Case Comm.Comm_Frame.BikiFrameType.ID_EEPROM_DATA
                                                    m_UsbEEpromDataBuffer = f_Frame
                                                    m_UsbEEpromDataEvent.Set()
                                                    m_UsbEEpromDataEvent2.Set()
                                                Case Comm.Comm_Frame.BikiFrameType.ID_FLASH_DATA
                                                    ' Console.WriteLine("Flash Data Recived!")
                                                    'Threading.Thread.Sleep(100)
                                                    'm_UsbFlashDataEvent.Reset()
                                                    m_UsbFlashDataBuffer = f_Frame
                                                    m_UsbFlashDataEvent.Set()
                                                    m_UsbFlashDataEvent2.Set()
                                                Case Comm.Comm_Frame.BikiFrameType.ID_LAST_COMMAND_STATUS
                                                    m_UsbLastCmdStatusBuffer = f_Frame
                                                    Queue.Synchronized(m_UsbLastCmdStatusBfr).Enqueue(f_Frame)
                                                    m_UsbLastCmdStatusEvent.Set()
                                                Case Comm_Frame.BikiFrameType.ID_GENERAL_SPECIFIC
                                                    m_UsbGeneralSpecificBuffer = f_Frame
                                                    m_UsbGeneralSpecificEvent.Set()
                                                Case Comm_Frame.BikiFrameType.ID_CONSULT_PASS
                                                    Console.WriteLine("Consult data has arrived")
                                                Case Else
                                                    Debug.Print("Something else arrived, unknown data")
                                            End Select
                                        ElseIf m_UsbRx(3) = &HA Then
                                            'Dim f_consult() As Byte = Nothing
                                            'If Not IsNothing(m_usbConsultPassArray) Then
                                            '    ReDim Preserve m_usbConsultPassArray(m_usbConsultPassArray.Length + m_RxBytes - 1)
                                            'Else
                                            '    ReDim m_usbConsultPassArray(m_RxBytes - 1)
                                            'End If
                                            'Stream.Synchronized(m_usbConsultPassArray).Write(f_Data, 6, m_RxBytes)
                                            If Not IsNothing(m_UsbConsultPassBuffer) Then
                                                ReDim Preserve m_UsbConsultPassBuffer(m_UsbConsultPassBuffer.Length + m_RxBytes - 1)
                                            Else
                                                ReDim m_UsbConsultPassBuffer(m_RxBytes - 1)
                                            End If
                                            Array.Copy(f_Data, 6, m_UsbConsultPassBuffer, m_UsbConsultPassBuffer.Length - m_RxBytes, m_RxBytes)
                                            ' Array.Copy(f_Data, 6, m_usbConsultPassArray, m_usbConsultPassArray.Length - m_RxBytes, m_RxBytes)
                                            'Array.Copy(f_Data, 6, f_consult, 0, m_RxBytes)
                                            'm_UsbConsultEvent.Reset()
                                            '  Console.WriteLine("Consult: " & cv_StrFromBytes(f_consult))
                                            'm_UsbConsultPassBuffer = f_consult
                                            m_UsbConsultEvent.Set()
                                            m_UsbConsultEvent2.Set()

                                        End If
                                        ' Get the Frames ID
                                        m_UsbRx.RemoveRange(0, m_RxBytes + 10)
                                        m_RxStatus = 0
                                        If m_UsbRx.Count > 0 Then GoTo retry
                                    Else ' CRC FAILED!
                                        ' clear the frame header
                                        m_UsbRx.RemoveRange(0, m_RxBytes + 10)
                                        m_RxStatus = 0
                                        m_UsbCRCFailedEvent.Set()
                                        Debug.Print("Usb-Rcv: CRC Failed")
                                        If m_UsbRx.Count > 0 Then GoTo retry
                                    End If
                                Else ' Headers and Footers Failed
                                    m_UsbRx.RemoveRange(0, m_RxBytes + 6)
                                    m_RxStatus = 0
                                    m_UsbHeadersFailedEvent.Set()
                                    Debug.Print("Usb-Rcv: Head/Foot Failed")
                                    GoTo retry
                                End If
                            End If
                        End If
                    Else
                        Debug.Print("Rcv-Thread: Bytes Expected but non recieved")
                    End If
                    If frameExists() Then GoTo retry
                Catch ex As Exception
                    RaiseEvent CommunicationExceptionEventHandler(Me, New UsbCommunicationStatusEventArgs("Exception caught in main communication handler", True, False))
                    Debug.Print("Exception in Recieve thread!!! BIG PROBLEM!")
                End Try
            Loop
            m_usbRxTimer.Stop()
            Debug.Print("Rx thread ended")
        End Sub
        '' checks if a full frame exists in the buffer...
        Private Function frameExists() As Boolean
            Dim f_Bytes As UInt16
            If m_UsbRx.Count >= 6 AndAlso (m_UsbRx(0) = &HAA And _
                   m_UsbRx(1) = &HA5) Then
                f_Bytes = (m_UsbRx(4) * &H100) Or m_UsbRx(5)
                If f_Bytes < MaxRxPacket + 50 AndAlso _
                   m_UsbRx.Count >= f_Bytes + 10 AndAlso _
                   (m_UsbRx(f_Bytes + 9) = &H5A And _
                   m_UsbRx(f_Bytes + 8) = &H55) Then
                    Return True
                End If
            End If
            Return False
        End Function

#End Region

#Region "Send/Recieve Functions"
        ''' <summary>
        ''' Sends the frame off, and passes back the array of the response if nothing than Last Command status. will throw any exceptions generated also. they need to be cought
        ''' </summary>
        ''' <param name="oArray">array to output the return to</param>
        ''' <param name="clearBuffers"></param>
        ''' <param name="RetryNum">Number of retries to allow for both timeout, crc and bad headers</param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Friend Function SendFrame(ByVal Frame As Comm_Frame, Optional ByRef oArray As Byte() = Nothing, Optional ByVal clearBuffers As Boolean = True, Optional ByVal RetryNum As Integer = 1) As Comm_Frame.BikiFrameResponse
            Dim nCode As Comm_Frame.BikiFrameResponse = Comm_Frame.BikiFrameResponse.CMD_OK
            Dim WriteTries As Integer = 2
            Try
                If Me.disposedValue Then
                    Return Comm_Frame.BikiFrameResponse.BUFFER_FULL
                End If
                ' check to see if its actualy OK to send shit. dont want two threads sending commands at once
                Dim f_wait As Comm_Frame.WaitValue
                Dim f_Waits(2) As WaitHandle
                f_Waits(0) = m_UsbLastCmdStatusEvent
                f_Waits(1) = m_UsbCRCFailedEvent
                f_Waits(2) = m_UsbHeadersFailedEvent

                If clearBuffers Then
                    ' Reset the events before we stop on them!
                    m_UsbLastCmdStatusEvent.Reset()
                    m_UsbCRCFailedEvent.Reset()
                    m_UsbHeadersFailedEvent.Reset()

                    ' Clear out any buffers we need to..
                    Select Case Frame.Response
                        Case Comm_Frame.BikiFrameType.ID_EEPROM_DATA
                            m_UsbEEpromDataEvent.Reset()
                            m_UsbEEpromDataBuffer = Nothing
                        Case Comm_Frame.BikiFrameType.ID_FLASH_DATA
                            m_UsbFlashDataEvent.Reset()
                            m_UsbFlashDataBuffer = Nothing
                        Case Comm_Frame.BikiFrameType.ID_GENERAL_SPECIFIC
                            m_UsbGeneralSpecificEvent.Reset()
                            m_UsbGeneralSpecificBuffer = Nothing
                        Case Comm_Frame.BikiFrameType.ID_LAST_COMMAND_STATUS
                            Queue.Synchronized(m_UsbLastCmdStatusBfr).Clear()
                            m_UsbLastCmdStatusBuffer = Nothing
                        Case Comm_Frame.BikiFrameType.ID_CONSULT_PASS
                            m_UsbConsultPassBuffer = Nothing
                            m_UsbConsultEvent.Reset()
                        Case Comm_Frame.BikiFrameType.eMsgIdLogData
                            m_UsbDataLogBuffer = Nothing
                            m_UsbDataLogEvent.Reset()
                    End Select
                End If

                If Frame.Response <> Comm_Frame.BikiFrameType.ID_LAST_COMMAND_STATUS Then
                    ReDim Preserve f_Waits(3)
                    Select Case Frame.Response
                        Case Comm_Frame.BikiFrameType.ID_EEPROM_DATA
                            f_Waits(3) = m_UsbEEpromDataEvent
                        Case Comm_Frame.BikiFrameType.ID_FLASH_DATA
                            f_Waits(3) = m_UsbFlashDataEvent
                        Case Comm_Frame.BikiFrameType.ID_GENERAL_SPECIFIC
                            f_Waits(3) = m_UsbGeneralSpecificEvent
                        Case Comm_Frame.BikiFrameType.ID_CONSULT_PASS
                            f_Waits(3) = m_UsbConsultEvent
                        Case Comm_Frame.BikiFrameType.eMsgIdLogData
                            f_Waits(3) = m_UsbDataLogEvent
                    End Select
                    If Frame.Response = Comm_Frame.BikiFrameType.ID_CONSULT_PASS Or _
                       Frame.Response = Comm_Frame.BikiFrameType.ID_CONSULT_INTEGRATED Then
                        ' Ignore bad heads for consult bypass mode. so many packets come thru errors
                        ' occur, acceptable errors. Ignore them
                        f_Waits(2) = f_Waits(3)
                        ReDim Preserve f_Waits(2)
                    End If
                End If

                ' Now actualy SEND the Frame.. idiot!
                If Not IsNothing(Frame.Data) Then
                    ' Lock Mutex!
                    If m_UsbTxRxMutex.WaitOne() Then '500, False) Then
                        ' set the timeout before issueing the command
                        'FT_SetTimeouts(mUsbHandle, Me.Timeout, Me.Timeout)
                        Dim f_return As FT_return
                        Try
                            Dim f_Written As Integer
                            Dim f_counter As Integer
                            f_return = FT_Write_Bytes(mUsbHandle, Frame.Data(0), Frame.Data.Length, f_Written)
doAgain:                    f_counter += f_Written
                            If f_return = FT_return.FT_OK And f_counter <> Frame.Data.Length Then
                                f_return = FT_Write_Bytes(mUsbHandle, Frame.Data(f_counter), Frame.Data.Length - f_counter, f_Written)
                                Debug.Print("Writing again!!!!!!!!!!!!!!!!!!!!!")
                                If WriteTries > 0 Then
                                    WriteTries -= 1
                                    GoTo doAgain
                                Else
                                    Throw New USB_exceptions("Unable to write data")
                                End If
                            End If
                        Catch ex As Exception

                        Finally
                            ' Release the current mutex
                            m_UsbTxRxMutex.ReleaseMutex()
                        End Try
                    Else
                        Dim f_UsbExcept As New USB_exceptions(FT_return.FT_OTHER_ERROR)
                    End If
                End If
                ' Console.WriteLine("Waiting for data to arrive")
                ' Now wait for the reply fool!
                f_wait = WaitHandle.WaitAny(f_Waits, Timeout * 2, True)
                If f_wait <> WaitHandle.WaitTimeout Then
                    If f_wait = Comm_Frame.WaitValue.WV_CRCFAIL Then ' --------------- CRC Failed
                        'Console.WriteLine("COMM_FRAME: CRC Failed")
                        Throw New Comm_Exceptions(Comm_Frame.BikiFrameResponse.CMD_CRC_FAILED, Comm_Frame.BikiFrameID.ID_PC)
                        nCode = BK_return.BK_IO_CRC_FAILED
                        'Throw New Comm_Exceptions(BikiFrameResponse.CMD_CRC_FAILED, BikiFrameType.ID_PC)
                    ElseIf f_wait = Comm_Frame.WaitValue.WV_HEADERFAIL AndAlso m_UsbHeadersFailedEvent Is f_Waits(2) Then ' -------- Headers Failed
                        'Console.WriteLine("COMM_FRAME: HEAD FAIL")
                        nCode = Comm_Frame.BikiFrameResponse.CMD_BAD_HEADS
                        Throw New Comm_Exceptions(Comm_Frame.BikiFrameResponse.CMD_BAD_HEADS, Comm_Frame.BikiFrameID.ID_PC)
                    ElseIf f_wait = Comm_Frame.WaitValue.WV_LASTCMD Then ' ----------- Last Command Status
                        ' Console.WriteLine("COMM_FRAME: Last Cmd")
                        Dim f_Frame As Comm_Frame = Queue.Synchronized(m_UsbLastCmdStatusBfr).Dequeue
                        If Not IsNothing(f_Frame) Then
                            Dim f_Except As New Comm_Exceptions(f_Frame.ResponseActual, f_Frame.IDFrom)
                        End If
                        nCode = f_Frame.ResponseActual
                    Else ' ------------------------------------------------ Specific Return request
                        ' do the stuff here
                        ' return the optional array reference here...

                        Dim f_Frame As Comm_Frame = Nothing
                        Select Case Frame.Response
                            Case Comm_Frame.BikiFrameType.eMsgIdLogData
                                f_Frame = m_UsbDataLogBuffer
                                m_UsbDataLogBuffer = Nothing
                            Case Comm_Frame.BikiFrameType.ID_EEPROM_DATA
                                'Console.WriteLine("COMM_FRAME: EEPROM Else")
                                f_Frame = m_UsbEEpromDataBuffer
                                m_UsbEEpromDataBuffer = Nothing
                            Case Comm_Frame.BikiFrameType.ID_FLASH_DATA
                                'Console.WriteLine("COMM_FRAME: FLASH Else")
                                f_Frame = m_UsbFlashDataBuffer
                                m_UsbFlashDataBuffer = Nothing
                            Case Comm_Frame.BikiFrameType.ID_GENERAL_SPECIFIC
                                'Console.WriteLine("COMM_FRAME: GENERAL Else")
                                f_Frame = m_UsbGeneralSpecificBuffer
                                m_UsbGeneralSpecificBuffer = Nothing
                            Case Comm_Frame.BikiFrameType.ID_CONSULT_PASS
                                ' Console.WriteLine("COMM_FRAME: CONSULT Else")
                                '   oArray = m_usbConsultPassArray.GetBuffer()
                                If IsNothing(m_UsbConsultPassBuffer) Then
                                    oArray = Nothing
                                Else
                                    oArray = m_UsbConsultPassBuffer.Clone 'ArrayList.Synchronized(m_UsbConsultPassBuffer).ToArray(GetType(Byte))
                                End If
                        End Select
                        If Not IsNothing(f_Frame) Then oArray = f_Frame.PayLoad(False)
                    End If
                Else
                    Debug.Print("Recieve: " & cv_HexFromBytes(m_UsbRx.ToArray(GetType(Byte))))
                    nCode = Comm_Frame.BikiFrameResponse.CMD_TIMEOUT
                    Throw New Comm_Exceptions(Comm_Frame.BikiFrameResponse.CMD_TIMEOUT, Comm_Frame.BikiFrameID.ID_PC)
                End If
            Catch exUsb As USB_exceptions
                If exUsb.Value = FT_return.FT_IO_TIMEOUT And RetryNum > 0 Then
                    Thread.Sleep(10)
                    SendFrame(Frame, oArray, True, RetryNum - 1)
                Else
                    Throw exUsb
                End If
                nCode = Comm_Frame.BikiFrameResponse.CMD_FAILED
                mCommunicationInitialised = False
                'If exUsb.Value <> FT_return.FT_OK Then m_BikiInfo.Initialised = False
            Catch exComm As Comm_Exceptions
                ' Auto Retry this crap again if retry num is greater than zero
                If (exComm.Response = Comm_Frame.BikiFrameResponse.CMD_BAD_HEADS Or _
                   exComm.Response = Comm_Frame.BikiFrameResponse.CMD_CRC_FAILED Or _
                   exComm.Response = Comm_Frame.BikiFrameResponse.CMD_TOOBIG Or _
                   exComm.Response = Comm_Frame.BikiFrameResponse.CMD_INCOMPLETE Or _
                   exComm.Response = Comm_Frame.BikiFrameResponse.CMD_TIMEOUT Or _
                   exComm.Response = Comm_Frame.BikiFrameResponse.CMD_UNKNOWN) _
                   And RetryNum > 0 _
                Then
                    nCode = SendFrame(Frame, oArray, True, RetryNum - 1)
                ElseIf exComm.Response = Comm_Frame.BikiFrameResponse.CMD_TIMEOUT Then
                    ' Me.mCommunicationInitialised = False
                    'Throw New USB_exceptions("Communication Dropped Out")
                    nCode = Comm_Frame.BikiFrameResponse.CMD_FAILED
                ElseIf exComm.Response <> Comm_Frame.BikiFrameResponse.CMD_OK Then
                    'Throw exComm
                    nCode = exComm.Response 'Comm_Frame.BikiFrameResponse.CMD_FAILED
                End If
            Finally

            End Try
            Return nCode
        End Function

        Private Function read_usb(Optional ByVal RxBytes As Integer = 0) As Byte()
            Dim f_BytesInBuffer As Integer = 0
            FT_GetQueueStatus(mUsbHandle, f_BytesInBuffer)
            If RxBytes = 0 And f_BytesInBuffer > 0 Then
                Dim retBytes(f_BytesInBuffer - 1) As Byte
                If FT_Read_Bytes(Me.mUsbHandle, retBytes(0), f_BytesInBuffer, RxBytes) = FT_return.FT_OK Then
                    ReDim Preserve retBytes(RxBytes - 1)
                    Return retBytes
                End If
            ElseIf RxBytes > 0 Then
                Dim retBytes(RxBytes - 1) As Byte
                If FT_Read_Bytes(mUsbHandle, retBytes(0), RxBytes, RxBytes) = FT_return.FT_OK Then
                    If RxBytes > 0 Then
                        ReDim Preserve retBytes(RxBytes - 1)
                        ' Console.WriteLine("USB Read {0:G} bytes: " & cv_HexFromBytes(retBytes), RxBytes)
                        Return retBytes
                    End If
                End If
            End If
            Return Nothing
        End Function

        <Obsolete()> _
        Friend Function SendRawFrame(ByVal Str_ As String, ByRef Return_() As Byte, ByVal retLen As Integer) As Boolean
            Dim f_cmd() As Byte = cv_BytesFromHex(Str_)
            If BikiRom_sndCmd(m_UsbCommHandler.Handle, f_cmd, Return_, f_cmd.Length, retLen) = FT_return.FT_OK Then
                Return True
            Else
                Return False
            End If
        End Function
        ''' <summary>
        ''' Send a command to the bikirom USB device and check it gives the reply given into the function
        ''' </summary>
        ''' <param name="inputStr">Command as a Hex String to send to BikiRom</param>
        ''' <param name="replyStr">BikiRom Reply Hex String validated against</param>
        ''' <returns>True if the replyStr is whats returned</returns>
        ''' <remarks></remarks>
        ''' 
        Friend Function SendRawFrame(ByVal inputStr As String, ByVal replyStr As String) As Boolean
            Dim f_cmd() As Byte = cv_BytesFromHex(inputStr)
            Dim f_reply() As Byte = cv_BytesFromHex(replyStr)
            Dim f_return(f_reply.Length - 1) As Byte
            Dim f_result As Boolean = True
            If BikiRom_sndCmd(m_UsbCommHandler.Handle, f_cmd, f_return, f_cmd.Length, f_reply.Length) = FT_return.FT_OK Then
                For i As Integer = 0 To UBound(f_reply)
                    If f_reply(i) <> f_return(i) Then f_result = False
                Next
                Return f_result
            Else
                Return False
            End If
        End Function
        <Obsolete()> _
        Friend Function SendRawFrame(ByVal Str_ As String, ByVal retLen As Integer) As Boolean
            Dim f_cmd() As Byte = cv_BytesFromHex(Str_)
            Dim f_return(0 To retLen) As Byte
            If BikiRom_sndCmd(m_UsbCommHandler.Handle, f_cmd, f_return, f_cmd.Length, retLen) = FT_return.FT_OK Then
                Return True
            Else
                Return False
            End If
        End Function
        <Obsolete()> _
        Friend Function SendRawFrame(ByVal Str_ As String) As Boolean
            Dim f_cmd() As Byte = cv_BytesFromHex(Str_)
            Dim f_return(0 To 1) As Byte
            If BikiRom_sndCmd(m_UsbCommHandler.Handle, f_cmd, f_return, f_cmd.Length, 0) = FT_return.FT_OK Then
                Return True
            Else
                Return False
            End If
        End Function
        <Obsolete()> _
        Friend Function SendRawFrame(ByRef Send_() As Byte, ByRef Return_() As Byte, ByVal sendLen As Integer, ByVal retLen As Integer) As Boolean
            If BikiRom_sndCmd(Me.mUsbHandle, Send_, Return_, sendLen, retLen) = FT_return.FT_OK Then
                Return True
            Else
                Return False
            End If
        End Function

        Private Function BikiRom_sndCmd(ByRef f_lngHandle As Integer, ByRef Send_() As Byte, ByRef Return_() As Byte, ByVal sendLen As Integer, ByVal retLen As Integer) As FT_return
            Dim f_retCount As Integer
            Dim flTimedout As Boolean = False
            Dim flFatalError As Boolean = False
            Dim lngTotalBytesRead As Integer = 0
            Dim ftStatus As Short
            Dim lngBytesRead As Integer = 0
            Dim byteArray(258) As Byte
            Dim arrayCursor As Short = 0
            Dim i As Short
            Dim fReturn As FT_return = FT_return.FT_OK

            '  If sendLen >= 1 Then
            'FT_Purge(lngHandle, FT_Purg.FT_PURGE_RX + FT_Purg.FT_PURGE_TX)
            'End If
            'Debug.Print ("cmd: " & cv_HexFromString(Send_) & " length: " & sendLen)
            '********************
            '** Send Command Code
            If sendLen >= 1 Then
                fReturn = FT_Write_Bytes(f_lngHandle, Send_(0), sendLen, f_retCount)
                If fReturn <> FT_return.FT_OK Then
                    Debug.Write("Error writing bytes to USB CHIP")
                    Return fReturn
                End If
            End If
            If retLen <> 0 Then
                flTimedout = False
                flFatalError = False

                '******************
                '** Wait for number of bytes code
                lngTotalBytesRead = 0
                Do
                    lngBytesRead = 0
                    ftStatus = FT_Read_Bytes(f_lngHandle, byteArray(0), retLen, lngBytesRead)
                    ' Debug.Print("FT_Read - send# :" & retLen & " Read: " & lngTotalBytesRead)
                    If (ftStatus = FT_return.FT_OK) Or (ftStatus = FT_return.FT_IO_ERROR) Then
                        If lngBytesRead > 0 Then
                            For i = 1 To lngBytesRead
                                Return_(arrayCursor) = byteArray(i - 1)
                                arrayCursor += 1
                            Next
                            lngTotalBytesRead += lngBytesRead
                            retLen -= lngBytesRead
                        Else
                            Return FT_return.FT_IO_TIMEOUT
                            flTimedout = True
                        End If
                    Else
                        Return FT_return.FT_IO_FAILED
                        flFatalError = True
                    End If
                Loop Until (lngTotalBytesRead >= retLen) Or (flTimedout = True) Or (flFatalError = True)
                'Else
                'FT_Purge(f_lngHandle, FT_Purg.FT_PURGE_RX)
            End If
            '*******************
            '** Return Code
            Return FT_return.FT_OK
        End Function

#End Region

#Region " IDisposable Support "

        Private disposedValue As Boolean = False        ' To detect redundant calls

        ' IDisposable
        Protected Overridable Sub Dispose(ByVal disposing As Boolean)
            If Not Me.disposedValue Then
                If disposing Then
                    ' TODO: free unmanaged resources when explicitly called
                End If

                Me.m_OnlineTimer.Dispose()

                CloseRecievers()

                ' Kill the Communication thread
                Me.Close()

                ' Clear out all the waithandles and what not
                m_UsbFlashDataEvent.Close()
                m_UsbEEpromDataEvent.Close()
                m_UsbLastCmdStatusEvent.Close()
                m_UsbCRCFailedEvent.Close()
                m_UsbHeadersFailedEvent.Close()
                m_UsbConsultEvent.Close()
                m_UsbStreamEvent.Close()
                m_UsbGeneralSpecificEvent.Close()

            End If
            Me.disposedValue = True
        End Sub

        ' This code added by Visual Basic to correctly implement the disposable pattern.
        Public Sub Dispose() Implements IDisposable.Dispose
            ' Do not change this code.  Put cleanup code in Dispose(ByVal disposing As Boolean) above.
            Dispose(True)
            GC.SuppressFinalize(Me)
        End Sub
#End Region


    End Class

End Namespace